/*
 * Copyright (C) 2011-2013 Eric Lasota
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef __RDX_MARSHAL_HPP__
#define __RDX_MARSHAL_HPP__

#include "rdx_basictypes.hpp"

namespace RDX
{
	struct OperationContext;

	namespace ObjectManagement
	{
		struct IObjectManager;
	}

	namespace Programmability
	{
		union RuntimeStackValue;
		struct RuntimeThread;
	}

	namespace Marshaling
	{
		struct ExportedCallEnvironment
		{
			RDX::OperationContext *ctx;
			RDX::Programmability::RuntimeThread *thread;
			RDX::ObjectManagement::IObjectManager *objm;
			int status;

			int Throw(RDX::Programmability::Exception *ex);
			int Throw(const char *exObjectName);
		};

		template<class _T>
		union Value
		{
			UInt8 _rawValue[sizeof(_T)];
			Programmability::RuntimeStackValue asStackValues[(sizeof(_T) + (Programmability::ALIGN_RuntimeStackValue-1)) / sizeof(Programmability::RuntimeStackValue)];

			inline _T &GetValue()
			{
				return *reinterpret_cast<_T *>(_rawValue);
			}

			inline const _T &GetValue() const
			{
				return *reinterpret_cast<const _T *>(_rawValue);
			}
		};

		template<class _T>
		_T *ParametersFromPRV(Programmability::RuntimeStackValue *prv)
		{
			return reinterpret_cast<_T*>(
				reinterpret_cast<UInt8*>(prv) - sizeof(_T));
		}

		template<class _T>
		_T *ReturnValuesFromPRV(Programmability::RuntimeStackValue *prv)
		{
			return reinterpret_cast<_T*>(prv);
		}

		template<class sReturnValues, class sParams>
		struct ReturnAndParameterFrame
		{
			sParams parameters;
			sReturnValues returnValues;
		};

#define RDX_MARSHAL_SIMPLE					NULL, 0, 0
#define RDX_MARSHAL_NOPARAMETERS(pReturn)	(&(pReturn)), 0, 0
#define RDX_MARSHAL_NORETURN(pParameters)	(&(pParameters)), sizeof(*(pParameters)), 0
#define RDX_MARSHAL_FRAME(pFrameMarshal)	(&(pFrameMarshal)), sizeof((pFrameMarshal)->parameters), sizeof((pFrameMarshal)->returnValues)

		struct CallFrame0
		{
		};

		template<class _PT1>
		struct CallFrame1
		{
			Value<_PT1> value1;
		};

		template<class _PT1, class _PT2>
		struct CallFrame2
		{
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		
		template<class _PT1, class _PT2, class _PT3>
		struct CallFrame3
		{
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4>
		struct CallFrame4
		{
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5>
		struct CallFrame5
		{
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6>
		struct CallFrame6
		{
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7>
		struct CallFrame7
		{
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8>
		struct CallFrame8
		{
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9>
		struct CallFrame9
		{
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10>
		struct CallFrame10
		{
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
		
		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10, class _PT11>
		struct CallFrame11
		{
			Value<_PT11> value11;
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};

		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10, class _PT11, class _PT12>
		struct CallFrame12
		{
			Value<_PT12> value12;
			Value<_PT11> value11;
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};

		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10, class _PT11, class _PT12, class _PT13>
		struct CallFrame13
		{
			Value<_PT13> value13;
			Value<_PT12> value12;
			Value<_PT11> value11;
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};

		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10, class _PT11, class _PT12, class _PT13, class _PT14>
		struct CallFrame14
		{
			Value<_PT14> value14;
			Value<_PT13> value13;
			Value<_PT12> value12;
			Value<_PT11> value11;
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};

		template<class _PT1, class _PT2, class _PT3, class _PT4, class _PT5, class _PT6, class _PT7, class _PT8, class _PT9, class _PT10, class _PT11, class _PT12, class _PT13, class _PT14, class _PT15>
		struct CallFrame15
		{
			Value<_PT15> value15;
			Value<_PT14> value14;
			Value<_PT13> value13;
			Value<_PT12> value12;
			Value<_PT11> value11;
			Value<_PT10> value10;
			Value<_PT9> value9;
			Value<_PT8> value8;
			Value<_PT7> value7;
			Value<_PT6> value6;
			Value<_PT5> value5;
			Value<_PT4> value4;
			Value<_PT3> value3;
			Value<_PT2> value2;
			Value<_PT1> value1;
		};
	}
}

#include "rdx_programmability.hpp"

namespace RDX
{
	namespace Marshaling
	{
		inline int ExportedCallEnvironment::Throw(Programmability::Exception *ex)
		{
			this->thread->ex = ex;
			this->status = Programmability::RuntimeState::Exception;
			return Programmability::RuntimeState::Exception;
		}

		inline int ExportedCallEnvironment::Throw(const char *exObjectName)
		{
			const Programmability::String *str = this->objm->CreateStringASCII(this->ctx, exObjectName, -1, true);
			void *exObj = this->objm->LookupSymbolSimple(this->ctx, str);
			return this->Throw(static_cast<Programmability::Exception *>(exObj));
		}
	}
}

#endif
